<?php

class Project_String {
	public static function formatNumber($number, $decimals = 2) {
		return (float) $number == (int) $number
			? number_format($number, null, null, ' ')
			: number_format($number, $decimals, ',', ' ');
	}

	public static function getRandomString($length) {
		$letters = 'abcdefghijklmnopqrstuvwxyz';
		$numbers = '0123456789';
		$symbol = '';
		$result = '';

		for ($i = 0; $i < $length; $i++) {
			if (0 == rand(0, 3)) {
				$symbol = $letters{rand(0, strlen($letters) - 1)};
				/*if (0 == rand(0, 3)) $symbol = strtoupper($symbol);*/
			} else {
				$symbol = $numbers{rand(0, strlen($numbers) - 1)};
			}
			$result .= $symbol;
		}
		return $result;
	}

	public static function getRandomStringOptimized($length) {
		$consonant = 'bcdfghjklmnpqrstvwxz';
		$vowel = 'aeiouy';
		$result = '';
		$pairs = ($length == 2) ? 1 : floor($length / 2) - 1;

		for ($i = 0; $i < $pairs; $i++) {
			$result .= $consonant[rand(0, strlen($consonant) - 1)];
			$result .= $vowel[rand(0, strlen($vowel) - 1)];
		}
		if ($length % 2 != 0) $result .= $consonant[rand(0, strlen($consonant) - 1)];
		if ($length > 2) $result .= rand(0, 9) . rand(0, 9);

		return $result;
	}

	public static function transformCaseToUnderline($value) {
		$result = '';
		for ($i = 0; $i < strlen($value); $i++) {
			if (
				$i != 0 &&
				!in_array($value{$i}, array('_', '-')) &&
				$value{$i} == strtoupper($value{$i})
			) {
				$result .= '_';
			}
			$result .= strtolower($value{$i});
		}
		return $result;
	}

	public static function transformUnderlineToCase($value, $isFirstUppercased = false) {
		$result = '';
		for ($i = 0; $i < strlen($value); $i++) {
			if ($value{$i} == '_') {
				if ($i != 0 && $i != strlen($value) - 1) {
					$result .= strtoupper($value{++$i});
				}
			} else {
				$result .= $value{$i};
			}
		}
		if ($result != '' && $isFirstUppercased) {
			$result{0} = strtoupper($result{0});
		}
		return $result;
	}

	/*
	 * Распознаются следующие форматы:
	 * позавчера, вчера, сегодня, завтра, послезавтра
	 * 1 августа, 1 авг, 10/10
	 * 1 авг 2009, 1 августа 2009, 1 августа 2009 г., 1 августа 2009 года
	 * 01.10.2009, 01.10.09, 01/10/2009, 01/10/09, 2009-10-01
	 */
	public static function toDate($value) {
		$value = trim($value);
		$todayNoon = mktime(12, 0, 0, date('m'), date('d'), date('Y'));
		$match = array();

		switch (mb_strtolower($value)) {
			case 'позавчера':	return $todayNoon - 60 * 60 * 24 * 2;
			case 'вчера':		return $todayNoon - 60 * 60 * 24;
			case 'сегодня':		return $todayNoon;
			case 'завтра':		return $todayNoon + 60 * 60 * 24;
			case 'послезавтра':	return $todayNoon + 60 * 60 * 24 * 2;
		}

		preg_match('/^([0-9]{1,2})[.\/\-]([0-9]{1,2})(?:[.\/\-]([0-9]{2,4}))?$/', $value, $match);
		if ($match) {
			$day = $match[1];
			$month = $match[2];
			$year = empty($match[3]) ? date('Y') : $match[3];

			if (30 >= $year) $year += 2000;
			elseif (100 > $year) $year += 1900;

			if (self::checkDate($year, $month, $day)) {
				return mktime(12, 0, 0, $month, $day, $year);
			}
		}

		preg_match('/^([0-9]{4})[.\/\-]([0-9]{1,2})[.\/\-]([0-9]{1,2})$/', $value, $match);
		if ($match) {
			list(,$year ,$month ,$day) = $match;

			if (30 >= $year) $year += 2000;
			elseif (100 > $year) $year += 1900;

			if (self::checkDate($year, $month, $day)) {
				return mktime(12, 0, 0, $month, $day, $year);
			}
		}

		$day = $month = $year = 0;
		preg_match('/([0-9]{2,4}) ?(года|г\.|г)/', $value, $match);
		if ($match) {
			$year = $match[1];

			if (30 >= $year) $year += 2000;
			elseif (100 > $year) $year += 1900;

			$value = trim(str_replace($match[0], '', $value));
		}

		$date = explode(' ', $value);
		if (
			1 < count($date) &&
			4 > count($date) &&
			!(3 == count($date) && 0 < $year)
		) {
			$day = $date[0];
			$month = Project_Date::guessMonth($date[1]);

			if (isset($date[2])) $year = $date[2];
			elseif (0 == $year) $year = date('Y');

			if (self::checkDate($year, $month, $day)) {
				return mktime(12, 0, 0, $month, $day, $year);
			}
		}

		return false;
	}

	public static function checkDate($year, $month, $day) {
		return
			0 < $day && 32 > $day &&
			0 < $month && 13 > $month &&
			date('Y') - 10 < $year && date('Y') + 10 > $year;
	}

	/*
	 * 999 миллиардов 33 миллиона 21 тысяча 3 рубля
	 */
	public static function fromNumber($number) {
		$result = '';
		$number = (int) $number;

		$billion = 1000000000;
		$billions = floor($number / $billion);
		if (0 < $billions) {
			$append = self::getNumberTitle($billions, 1);
			$result .= '' != $result ? ' ' . mb_strtolower($append) : $append;
			$result .= ' ' . self::getNumberLabel($billions, 'миллиардов', 'миллиард', 'миллиарда');
		}

		$million = 1000000;
		$millions = floor(($number - $billions * $billion) / $million);
		if (0 < $millions) {
			$append = self::getNumberTitle($millions, 1);
			$result .= '' != $result ? ' ' . mb_strtolower($append) : $append;
			$result .= ' ' . self::getNumberLabel($millions, 'миллионов', 'миллион', 'миллиона');
		}

		$thousand = 1000;
		$thousands = floor(($number - ($billions * $billion + $millions * $million)) / $thousand);
		if (0 < $thousands) {
			$append = self::getNumberTitle($thousands, 2);
			$result .= '' != $result ? ' ' . mb_strtolower($append) : $append;
			$result .= ' ' . self::getNumberLabel($thousands, 'тысяч', 'тысяча', 'тысячи');
		}

		$remainder = $number - ($billions * $billion + $millions * $million + $thousands * $thousand);
		$append = self::getNumberTitle($remainder, 1);
		$result .= '' != $result ? ' ' . mb_strtolower($append) : $append;
		$result .= ' ' . self::getNumberLabel($remainder, 'рублей', 'рубль', 'рубля');

		return $result;
	}

	public static function getNumberLabel($number, $case1, $case2, $case3) {
		$base = $number - floor($number / 100) * 100;
		$case = null;

		if ($base > 9 && $base < 20) {
			$case = $case1;
		} else {
			$remainder = $number - floor($number / 10) * 10;
			if (1 == $remainder) $case = $case2;
			elseif (0 < $remainder && 5 > $remainder) $case = $case3;
			else $case = $case1;
		}

		return $case;
	}

	public static function getNumberTitle($number, $sex) {
		if (999 < $number) return false;

		$titles = array(
			1   => array('Один', 'Одна'),
			2   => array('Два', 'Две'),
			3   => array('Три'),
			4   => array('Четыре'),
			5   => array('Пять'),
			6   => array('Шесть'),
			7   => array('Семь'),
			8   => array('Восемь'),
			9   => array('Девять'),
			10  => array('Десять'),
			11  => array('Одинадцать'),
			12  => array('Двенадцать'),
			13  => array('Тринадцать'),
			14  => array('Четырнадцать'),
			15  => array('Пятнадцать'),
			16  => array('Шестнадцать'),
			17  => array('Семнадцать'),
			18  => array('Восемнадцать'),
			19  => array('Девятнадцать'),
			20  => array('Двадцать'),
			30  => array('Тридцать'),
			40  => array('Сорок'),
			50  => array('Пятьдесят'),
			60  => array('Шестьедесят'),
			70  => array('Семьдесят'),
			80  => array('Восемьдесят'),
			90  => array('Девяносто'),
			100 => array('Сто'),
			200 => array('Двести'),
			300 => array('Триста'),
			400 => array('Четыреста'),
			500 => array('Пятьсот'),
			600 => array('Шестьсот'),
			700 => array('Семьсот'),
			800 => array('Восемьсот'),
			900 => array('Девятьсот')
		);

		$result = '';
		$sex--;
		$remainder = $number;

		if (isset($titles[$remainder])) {
			$append = isset($titles[$remainder][$sex]) ? $titles[$remainder][$sex] : $titles[$remainder][0];
			$result .= '' != $result ? ' ' . mb_strtolower($append) : $append;
			return $result;
		}

		$hundred = 100;
		$hundreds = floor($remainder / $hundred);
		if (0 < $hundreds) {
			$append = isset($titles[$hundreds * $hundred][$sex]) ? $titles[$hundreds * $hundred][$sex] : $titles[$hundreds * $hundred][0];
			$result .= '' != $result ? ' ' . mb_strtolower($append) : $append;
			$remainder -= $hundreds * $hundred;
		}

		if (isset($titles[$remainder])) {
			$append = isset($titles[$remainder][$sex]) ? $titles[$remainder][$sex] : $titles[$remainder][0];
			$result .= '' != $result ? ' ' . mb_strtolower($append) : $append;
			return $result;
		}

		$ten = 10;
		$tens = floor($remainder / $ten);
		if (0 < $tens) {
			$append = isset($titles[$tens * $ten][$sex]) ? $titles[$tens * $ten][$sex] : $titles[$tens * $ten][0];
			$result .= '' != $result ? ' ' . mb_strtolower($append) : $append;
			$remainder -= $tens * $ten;
		}

		if (isset($titles[$remainder])) {
			$append = isset($titles[$remainder][$sex]) ? $titles[$remainder][$sex] : $titles[$remainder][0];
			$result .= '' != $result ? ' ' . mb_strtolower($append) : $append;
			return $result;
		}

		return $result;
	}

	public static function translit($string) {
		$rus = array(
			'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd',
			'е' => 'e', 'ё' => 'e', 'ж' => 'j', 'з' => 'z', 'и' => 'i',
			'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n',
			'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't',
			'у' => 'u', 'ф' => 'f', 'х' => 'h', 'ц' => 'cz', 'ч' => 'ch',
			'ш' => 'sh', 'щ' => 'sch', 'ъ' => '', 'ы' => 'i', 'ь' => '',
			'э' => 'e', 'ю' => 'yu', 'я' => 'ia'
		);

		$result = '';
		for ($i = 0; $i < mb_strlen($string); $i++) {
			$char = mb_substr($string, $i, 1);

			if (isset($rus[$char])) {
				$result .= $rus[$char];

			} elseif (isset($rus[mb_strtolower($char)])) {
				$result .= ucfirst($rus[mb_strtolower($char)]);

			} else {
				$result .= $char;
			}
		}

		return $result;
	}

	public static function isEmail($email) {
		return
			(bool)
			preg_match('/^[0-9a-zA-Z_][0-9a-zA-Z_.-]*[0-9a-zA-Z_-]@([0-9a-zA-Z][0-9a-zA-Z-]*\.)+[a-zA-Z]{2,4}$/', $email);
	}

	public static function isNaturalNumber($number) {
		return (bool) preg_match('/^[1-9]+$/', $number);
	}

	public static function isNumber($number) {
		return (bool) preg_match('/^[0-9.,]+$/', $number);
	}

	public static function getNumber($value) {
		$number = str_replace(array(',', ' '), array('.', ''), $value);
		return self::isNumber($number) ? (float) $number : 0;
	}

	public static function cut($string, $length) {
		$result = '';

		if (mb_strlen($string) > $length) {
			$l = 0;

			foreach (explode(' ', $string) as $item) {
				$l += mb_strlen($item);
				if ($l >= $length) break;
				else $result .= ($result == '' ? '' : ' ') . $item;
			}

//			$result .= '&hellip;';
			$result .= '…';

		} else {
			$result = $string;
		}

		return $result;
	}
}
